package com.eunion.web.admin.controller;

import java.lang.management.ClassLoadingMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * JVM  信息输出.
 * 
 * @since 2017年1月7日
 */
@Controller
@RequestMapping(value = "/admin/jvm")
public class JvmController {

	private Logger logger = LoggerFactory.getLogger(getClass());

	private NumberFormat fmtI = new DecimalFormat("###,###", new DecimalFormatSymbols(Locale.ENGLISH));

	private NumberFormat fmtD = new DecimalFormat("###,##0.000", new DecimalFormatSymbols(Locale.ENGLISH));

	private final int MB = 1024 * 1024;

	/**
	 * 跳转到首页面.
	 * 
	 * @param model
	 *            a holder for model attributes 数据
	 * @return 首页页面
	 */
	@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
	protected String main(Model model) {
		model.addAttribute("JVM", getSummary());
		return "admin/jvm";
	}

	/**
	 * 获取JVM当前信息.
	 * http://blog.csdn.net/zhangren07/article/details/8350161
	 */
	public List<Object[]> getSummary() {
		//采集JVM 信息
		RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
		OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
		ThreadMXBean threads = ManagementFactory.getThreadMXBean();
		MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
		ClassLoadingMXBean cl = ManagementFactory.getClassLoadingMXBean();
		List<Object[]> jvmList = new ArrayList<Object[]>();

		jvmList.add(new Object[] {"osName", os.getName() + " V " + os.getVersion()});
		jvmList.add(new Object[] {"osArch", os.getArch()});
		jvmList.add(new Object[] {"osCores", os.getAvailableProcessors()});
		jvmList.add(new Object[] {"jvmName", runtime.getVmName() + " V " + runtime.getVmVersion()});
		jvmList.add(new Object[] {"jvmJavaVer", System.getProperty("java.version")});
		jvmList.add(new Object[] {"jvmVendor", runtime.getVmVendor()});
		jvmList.add(new Object[] {"jvmUptime", toDuration(runtime.getUptime())});
		jvmList.add(new Object[] {"threadsLive", threads.getThreadCount()});
		jvmList.add(new Object[] {"threadsDaemon", threads.getDaemonThreadCount()});
		jvmList.add(new Object[] {"threadsPeak", threads.getPeakThreadCount()});
		jvmList.add(new Object[] {"threadsTotal", threads.getTotalStartedThreadCount()});
		jvmList.add(new Object[] {"heapCurr", mem.getHeapMemoryUsage().getUsed() / MB + " MB"});
		jvmList.add(new Object[] {"heapMax", mem.getHeapMemoryUsage().getMax() / MB + " MB"});
		jvmList.add(new Object[] {"heapCommitted", mem.getHeapMemoryUsage().getCommitted() / MB + " MB"});
		jvmList.add(new Object[] {"clsCurrLoaded", cl.getLoadedClassCount()});
		jvmList.add(new Object[] {"clsLoaded", cl.getTotalLoadedClassCount()});
		jvmList.add(new Object[] {"clsUnloaded", cl.getUnloadedClassCount()});
		logger.debug("current jmvInfo is :{}", Arrays.asList(jvmList));
		return jvmList;
	}

	/**
	 * 转换为MB.
	 */
	protected String printSizeInMB(double size) {
		return fmtI.format((long) (size / 1024)) + " MB ytes";
	}

	/**
	 * 转换时间.
	 */
	protected String toDuration(double uptime) {
		uptime /= 1000;
		if (uptime < 60) {
			return fmtD.format(uptime) + " S";
		}
		uptime /= 60;
		if (uptime < 60) {
			long minutes = (long) uptime;
			String s = fmtI.format(minutes) + (minutes > 1 ? " minutes" : " minute");
			return s;
		}
		uptime /= 60;
		if (uptime < 24) {
			long hours = (long) uptime;
			long minutes = (long) ((uptime - hours) * 60);
			String s = fmtI.format(hours) + (hours > 1 ? " hours" : " hour");
			if (minutes != 0) {
				s += " " + fmtI.format(minutes) + (minutes > 1 ? " minutes" : " minute");
			}
			return s;
		}
		uptime /= 24;
		long days = (long) uptime;
		long hours = (long) ((uptime - days) * 24);
		String s = fmtI.format(days) + (days > 1 ? " days" : " day");
		if (hours != 0) {
			s += " " + fmtI.format(hours) + (hours > 1 ? " hours" : " hour");
		}
		return s;
	}

}
